/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ubc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
 *
 * @author Yan
 */

public class nio {

    // Reads from the channel associated with the key into the dst ByteBuffer
    public static int read(java.nio.channels.SelectionKey key, ByteBuffer dst) throws Exception {
        SocketChannel client = (SocketChannel) key.channel();
        int numRead = client.read(dst);
        return numRead;
    }

    // Writes an obj and it's lenght in bytes to the channel associated with the key
    public static int writeIncludingLength(java.nio.channels.SelectionKey key, Object obj) throws Exception{

        // Get the channel
        SocketChannel client = (SocketChannel) key.channel();

        // Allocate a buffer and write the length of the object to it
        ByteBuffer buf = ByteBuffer.allocate(4+getBytes(obj).length);
        buf.putInt(getBytes(obj).length);
        buf.put(getBytes(obj));
        buf.clear();

        // finally, write the object to the channel
        int numWrite = 0;
        while(buf.hasRemaining()) {
            numWrite += client.write(buf);
        }
        obj = null;
        buf = null;
        return numWrite;
    }

    // Writes a string to the channel associated with the key
    public static int writeString(java.nio.channels.SelectionKey key, String str) throws Exception{

        // Get the channel
        SocketChannel client = (SocketChannel) key.channel();

        ByteBuffer buf = ByteBuffer.wrap(str.getBytes());

        // finally, write the buffer to the channel
        int numWrite = 0;
        while(buf.hasRemaining()) {
            numWrite += client.write(buf);
        }
        str = null;
        buf = null;
        return numWrite;
    }


    // Closes the channel associated with the key and cancel the key
    public static void close(java.nio.channels.SelectionKey key) {
        key.attach(null);
        try {
            key.channel().close();
        } catch(Exception e) {
            System.out.println("nio.close.Exception");
            e.printStackTrace();
        }
        key.cancel();
    }

    // Returns the byte[] of an object
    public static byte[] getBytes(Object obj) throws java.io.IOException{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        oos.flush();
        oos.close();
        bos.close();
        byte [] data = bos.toByteArray();
        return data;
    }

        // Returns the object of a byte[]
    public static Object toObject(byte[] bytes){
        Object object = null;
        try{
            object = new java.io.ObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
        } catch(Exception e) {
            System.out.println("nio.toObject.Exception");
            e.printStackTrace();
            return null;
        }
        return object;
    }

}








//public class nio {
//
//    // Reads an object from the channel specified by the key
//    public static Object readWithProtocol(java.nio.channels.SelectionKey key) throws Exception {
//
//        // Get the channel
//        SocketChannel client = (SocketChannel) key.channel();
//
//        // Prepare a buffer
//        ByteBuffer intBuf = ByteBuffer.allocate(4);
//
//        // Read the status parameter from the channel
//        client.read(intBuf);
//        intBuf.clear();
//        int status = intBuf.getInt();
//        // If status is 1, throw a QuitException telling the program that it should quit
//        if(status == 1) {
//            throw new QuitException();
//        }
//        intBuf.clear();
//
//        // Find out the length of the data
//        client.read(intBuf);
//        intBuf.clear();
//        int length = intBuf.getInt();
//        // Allocate a buffer with capacity = length
//        ByteBuffer dataBuf = ByteBuffer.allocate( length );
//
//        // Read the bytes for the object
//        int numRead = 0;
//        while( true ) {
//            numRead += numRead = client.read(dataBuf);
//            if(numRead >= length) {
//                break;
//            }
//        }
//        return toObject(dataBuf.array());
//    }
//
//    // Writes an object to the channel specified by the key
//    public static int writeWithProtocol(java.nio.channels.SelectionKey key, Object obj, int status) throws Exception{
//
//        // Get the channel
//        SocketChannel client = (SocketChannel) key.channel();
//
//        // Allocate a buffer
//        int dataLength = getBytes(obj).length;
//        ByteBuffer buf = ByteBuffer.allocate(
//                4+ // Length of an int in bytes that represents the status
//                4+ // Length of an int in bytes that represents the length of the object in bytes
//                dataLength);
//
//        // put in the status
//        buf.putInt(status);
//
//        // put in the length of the data
//        buf.putInt(dataLength);
//
//        // put in the actual data
//        buf.put(getBytes(obj));
//
//        // prepare the buffer for writing
//        buf.clear();
//
//        // finally, write the buffer to the channel
//        int numWrite = 0;
//        while(buf.hasRemaining()) {
//            numWrite += client.write(buf);
//        }
//        return numWrite;
//    }
//
//    // Reads an object from the channel specified by the key
//    public static String readGnutellaPeers(java.nio.channels.SelectionKey key) throws Exception {
//
//        // Get the channel
//        SocketChannel client = (SocketChannel) key.channel();
//
//        // Prepare a buffer
//        ByteBuffer buf = ByteBuffer.allocate(10000);
//        while( client.read(buf) != -1 ) {}
//        String response = new String(buf.array());
//        return response;
//    }
//
//    // Reads an object from the channel specified by the key
//    public static void readGnutellaQueryHit(java.nio.channels.SelectionKey key) throws Exception {
//
//        // Get the channel
//        SocketChannel client = (SocketChannel) key.channel();
//        CrawlResult cr = (CrawlResult)key.attachment();
//
//        // Prepare buffers
//        ByteBuffer buf = ByteBuffer.allocate(50000);
//        int numRead = 0;
//        int i = 0;
//        while( true ) {
//            if ( (i=client.read(buf)) != -1 )
//                numRead += i;
//            else
//                break;
//        }
//
//        String s = new String(buf.array());
//        System.out.println(s);
//
//        int headerIndex = findEndOfHeader(buf.array());
//        System.out.println("headerIndex: " + headerIndex);
//
//        int curIndex = headerIndex;
//        while( true ) {
//            int qhitSize = ByteOrder.leb2int(subBuffer(buf.array(),curIndex+19,curIndex+23),0);
//            System.out.println("qhitSize: " + qhitSize);
//            if (qhitSize > 0 ) {
//                Crawler crawler = new Crawler();
//                crawler.processQueryHit(subBuffer(buf.array(), curIndex+23, curIndex+23+qhitSize), cr);
//                System.out.println(cr.getFilesList().toString());
//                curIndex += qhitSize + 23;
//            } else
//                break;
//        }
//
//        key.attach(cr);
//    }
//
//
//    // Writes an object to the channel specified by the key
//    public static int writeString(java.nio.channels.SelectionKey key, String str) throws Exception{
//
//        // Get the channel
//        SocketChannel client = (SocketChannel) key.channel();
//
//        ByteBuffer buf = ByteBuffer.wrap(str.getBytes());
//
//        // finally, write the buffer to the channel
//        int numWrite = 0;
//        while(buf.hasRemaining()) {
//            numWrite += client.write(buf);
//        }
//        return numWrite;
//    }
//
//    // Closes the channel associated with the key and cancel the key
//    public static void close(java.nio.channels.SelectionKey key) {
//        try {
//            key.channel().close();
//        } catch(Exception e) {
//            System.out.println("nio.close.Exception");
//            e.printStackTrace();
//        }
//        key.cancel();
//    }
//
//    // Returns the object of a byte[]
//    public static Object toObject(byte[] bytes){
//        Object object = null;
//        try{
//            object = new java.io.ObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
//        } catch(Exception e) {
//            System.out.println("nio.toObject.Exception");
//            e.printStackTrace();
//            return null;
//        }
//        return object;
//    }
//
//    // Returns the byte[] of an object
//    public static byte[] getBytes(Object obj) throws java.io.IOException{
//        ByteArrayOutputStream bos = new ByteArrayOutputStream();
//        ObjectOutputStream oos = new ObjectOutputStream(bos);
//        oos.writeObject(obj);
//        oos.flush();
//        oos.close();
//        bos.close();
//        byte [] data = bos.toByteArray();
//        return data;
//    }
//
//    private static byte[] subBuffer(byte[] buffer,int beginIndex,int endIndex){
//
//        if (beginIndex>buffer.length){
//            return null;
//        }
//        if (endIndex>buffer.length){
//            endIndex=buffer.length;
//        }
//        int bLen=endIndex-beginIndex;
//        byte[] result=new byte[bLen];
//
//        System.arraycopy(buffer,beginIndex,result,0,bLen);
//
//        return result;
//    }
//
//    private static int findEndOfHeader(byte[] packet){
//
//        for (int i=0;i<=packet.length-4;i++){
//            if (packet[i]=='\r' && packet[i+1]=='\n' && packet[i+2]=='\r' && packet[i+3]=='\n'){
//                return i+4;
//            }
//        }
//        return -1;
//    }
//
//}
